package com.xmz.cacheaside.service.impl;

import com.xmz.cacheaside.request.ProductQueryRequest;
import com.xmz.cacheaside.request.ProductUpdateRequest;
import com.xmz.cacheaside.request.Request;
import com.xmz.cacheaside.request.RequestQueue;
import com.xmz.cacheaside.service.RequestAsyncProcessService;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;

@Service
public class RequestAsyncProcessServiceImpl implements RequestAsyncProcessService {
    @Override
    public void process(Request request) throws InterruptedException {
        RequestQueue instance = RequestQueue.getInstance();
        Map<Integer, Boolean> flagMap = instance.getFlagMap();

        if (request instanceof ProductUpdateRequest){
            flagMap.put(request.getProductId(),true);
        }else if (request instanceof ProductQueryRequest){
            Boolean flag = flagMap.get(request.getProductId());
            if (flag ==null || flag){
                flagMap.put(request.getProductId(),false);
            }
            if(flag != null && !flag) {
                // 说明之前已经有一个读请求了
                return;
            }

            //做请求的路由 根据每个请求的商品id，路由到具体的队列中去
            ArrayBlockingQueue<Request> routingQueue = getRoutingQueue(request.getProductId());
            routingQueue.put(request);
        }

    }

    /**
     * 获取路由到的内存队列
     * @param productId 商品id
     * @return 内存队列
     */
    private ArrayBlockingQueue<Request> getRoutingQueue(Integer productId) {
        RequestQueue requestQueue = RequestQueue.getInstance();

        // 先获取productId的hash值
        String key = String.valueOf(productId);
        int h;
        int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

        // 对hash值取模，将hash值路由到指定的内存队列中，比如内存队列大小8
        // 用内存队列的数量对hash值取模之后，结果一定是在0~7之间
        // 所以任何一个商品id都会被固定路由到同样的一个内存队列中去的
        int index = (requestQueue.queueSize() - 1) & hash;

        System.out.println("===========日志===========: 路由内存队列，商品id=" + productId + ", 队列索引=" + index);

        return requestQueue.getQueue(index);
    }
}
